#pragma once

#include "zen_game_graphics.h"
#include "zen_game_sprite.h"
#include "zen_font.h"
#include <vector>
#include <mutex>

namespace Zen
{
	namespace Game
	{
		class LabelI
		{
		public:
			void SetText(std::string const& str);
			std::string const& GetText() const;

		protected:
			std::string mText;
			std::u32string mUnicodeText;
			bool mIsTextDirty = true;
		};

		class TextRender
		{
		public:
			virtual std::shared_ptr<Zen::Graphics::Texture> RenderTexture(std::u32string const& text, FontStyle const& style) = 0;
			virtual float GetScale() = 0;
			virtual ~TextRender() = default;
		};

		class DefaultTextRender : public TextRender
		{
		public:
			DefaultTextRender(std::shared_ptr<FontBrush> font_brush)
			{
				mFontBrush = font_brush;
			}
			float GetScale() override
			{
				return (mFontBrush ? (1.f / (float)mFontBrush->GetHeight()) : 0.f);
			}

			std::shared_ptr<Zen::Graphics::Texture> RenderTexture(std::u32string const& text, FontStyle const& style) override;

		protected:
			std::shared_ptr<FontBrush> mFontBrush;
		};

		/*!
	 @class
	 @abstract a font label. <br>
	 the label use a font to render view, it's a slowly operation. <br>
	 so not good for dynamic text.
	 */
		class TextLabel : public Sprite, public LabelI
		{
		public:
			TextLabel();

			virtual void Flush() override;
			virtual void OnReady(std::shared_ptr<RenderStack> stack, float interval) override;
			virtual void OnDraw() override;

		public:
			void SetTextRender(std::shared_ptr<TextRender> render);
			std::shared_ptr<TextRender> GetTextRender();
			void SetFontSize(float size);
			float GetFontSize() const;
			void SetFontStyle(FontStyle style);
			FontStyle const& GetFontStyle();

		protected:
			std::shared_ptr<TextRender> mRenderer;
			bool mIsRenderDirty = true;

			FontStyle mStyle;
			bool mIsStyleDirty = true;

		protected:
			float mFontSize = 16;
			bool mIsFontSizeDirty = true;

		protected:
			using Sprite::SetSize;
			using Sprite::SetTexture;
			using Sprite::SetTextureFrame;
		};
	} // namespace Game
} // namespace Zen

/// Tilemap

namespace Zen
{
	namespace Game
	{

		/**
	 00 -- 10
	 |      |
	 |      |
	 01 -- 11
	 */
		struct TileInfo
		{
			char32_t Unicode = 0;
			// position on texture. range=[0,1]
			float Left{};
			float Top{};
			float Right{};
			float Bottom{};

			// for vertex.
			// base line is on Left Bottoom.
			Point2 Size{ 1.0f, 1.0f };
			Point2 Move{};
			float Advance{ 1.0f };
		};

		class TileMap
		{
		public:
			static std::shared_ptr<TileMap> Generate(char32_t start_code, size_t x_count, size_t y_count);

			static std::shared_ptr<TileMap> Generate();

			void AddCharactor(TileInfo tc);

			TileInfo const* GetCharactor(char32_t code) const; // return nullptr if not exist.

			int GetVersion() const;

		protected:
			std::map<char32_t, TileInfo> mCharMap;
			int mVersion{};
		};

		class TileLabel : public FigureTexture, public LabelI
		{
		public:
			TileLabel();

			virtual void OnTextureChange() override;
			virtual void Flush() override;
			virtual void OnReady(std::shared_ptr<RenderStack> stack, float interval) override;
			virtual void OnDraw() override;

		public:
			void SetTileMap(std::shared_ptr<TileMap> tileMap);
			std::shared_ptr<TileMap> GetTileMap() const;

			void SetTileSize(Point2 tileSize);
			Point2 GetTileSize() const;

		protected:
			size_t UpdatePolygonVertex_();
			size_t UpdateTextureCoord_();

			Point2 mTileSize{};
			bool mIsTileSizeDirty{};

			std::shared_ptr<TileMap> mTileMap{};
			int mTileMapVersion{};
			bool mIsTileMapDirty{};

			int mFrameVersion{};
			bool mIsFrameDirty{};
			bool mIsEmpty{ true };

			std::vector<Point2> mVertexPoints;
			std::vector<Point2> mTextureCoordPoints;

		protected:
			using FigureTexture::SetSize;
		};
	} // namespace Game
} // namespace Zen
